﻿/*
 
Celerity: Sensory Overload
Copright 2012 by Adam Hill, David Gannon, Thomas Tamblyn & Patrick Ytting
Contact: adam.hill@outlook.com
Website: adamhill.org
Licence: MS-Pl Licence
  
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Sensors;
using Windows.Graphics.Display;

namespace Sensors
{
    public class SensorProxy
    {
        // Public events
        public event EventHandler OnShaken;
        public event EventHandler OnAccelReadingChanged;
        public event EventHandler OnGyroReadingChanged;
        public event EventHandler OnLightReadingChanged;
        public event EventHandler OnInclineReadingChanged;

        // Instance variables
        Accelerometer accel;
        Gyrometer gyro;
        LightSensor light;
        Inclinometer incline;
        const uint accelDesiredInterval = 16; // ms
        const uint gyroDesiredInterval = 16; // ms
        const uint lightDesiredInterval = 100; // ms
        const uint inclineDesiredInterval = 16; // ms

        // Properties
        public bool AccelAvailable { get; set; }
        public double AccelX { get; set; }
        public double AccelY { get; set; }
        public double AccelZ { get; set; }
        public DateTimeOffset AccelLastShaken { get; set; }
        public DateTimeOffset AccelLastReading { get; set; }
        public bool GyroAvailable { get; set; }
        public double GyroX { get; set; }
        public double GyroY { get; set; }
        public double GyroZ { get; set; }
        public DateTimeOffset GyroLastReading { get; set; }
        public bool LightAvailable { get; set; }
        public float LightLux { get; set; }
        public DateTimeOffset LightLastReading { get; set; }
        public bool InclineAvailable { get; set; }
        public double InclineX { get; set; }
        public double InclineY { get; set; }
        public double InclineZ { get; set; }
        public DateTimeOffset InclineLastReading { get; set; }

        // Constructor
        public SensorProxy()
        {
            InitAccel();
            //InitGyro(); // Disabled for now, could be used for future features
            //InitLight(); // Disabled for now, could be used for future features
            InitIncline();
        }

        void InitAccel()
        {
            // Instantiate
            accel = Accelerometer.GetDefault();
            AccelAvailable = accel != null;
            if (AccelAvailable)
            {
                // Set interval
                uint minAccelInterval = accel.MinimumReportInterval;
                accel.ReportInterval = minAccelInterval > accelDesiredInterval ? minAccelInterval : accelDesiredInterval;

                // Wire events
                accel.Shaken += accel_Shaken;
                accel.ReadingChanged += accel_ReadingChanged;

                // Accel defaults
                var accelReading = accel.GetCurrentReading();
                AccelX = accelReading.AccelerationX;
                AccelY = accelReading.AccelerationY;
                AccelZ = accelReading.AccelerationZ;
                AccelLastReading = accelReading.Timestamp;
            }
        }

        void InitGyro()
        {
            // Instantiate
            gyro = Gyrometer.GetDefault();
            GyroAvailable = gyro != null;
            if (GyroAvailable)
            {
                // Set interval
                uint minGyroInterval = gyro.MinimumReportInterval;
                gyro.ReportInterval = minGyroInterval > gyroDesiredInterval ? minGyroInterval : gyroDesiredInterval;

                // Wire events
                gyro.ReadingChanged += gyro_ReadingChanged;

                // Gyro defaults
                var gyroReading = gyro.GetCurrentReading();
                GyroX = gyroReading.AngularVelocityX;
                GyroY = gyroReading.AngularVelocityY;
                GyroZ = gyroReading.AngularVelocityZ;
                GyroLastReading = gyroReading.Timestamp;
            }
        }

        void InitLight()
        {
            // Instantiate
            light = LightSensor.GetDefault();
            LightAvailable = light != null;
            if (LightAvailable)
            {
                // Set interval
                uint minLightInterval = light.MinimumReportInterval;
                light.ReportInterval = minLightInterval > lightDesiredInterval ? minLightInterval : lightDesiredInterval;

                // Wire events
                light.ReadingChanged += light_ReadingChanged;

                // Defaults
                var lightReading = light.GetCurrentReading();
                LightLux = lightReading.IlluminanceInLux;
                LightLastReading = lightReading.Timestamp;
            }
        }

        void InitIncline()
        {
            // Instantiate
            incline = Inclinometer.GetDefault();
            InclineAvailable = incline != null;
            if (InclineAvailable)
            {
                // Set interval
                uint minInclineInterval = incline.MinimumReportInterval;
                incline.ReportInterval = minInclineInterval > inclineDesiredInterval ? minInclineInterval : inclineDesiredInterval;

                // Wire events
                incline.ReadingChanged += incline_ReadingChanged;

                // Defaults
                var inclineReading = incline.GetCurrentReading();
                InclineX = inclineReading.PitchDegrees;
                InclineY = inclineReading.RollDegrees;
                InclineZ = inclineReading.YawDegrees;
                InclineLastReading = inclineReading.Timestamp;
            }
        }

        // Event Handlers
        void accel_ReadingChanged(Accelerometer sender, AccelerometerReadingChangedEventArgs args)
        {
            AccelX = args.Reading.AccelerationX;
            AccelY = args.Reading.AccelerationY;
            AccelZ = args.Reading.AccelerationZ;
            AccelLastReading = args.Reading.Timestamp;
            if (OnAccelReadingChanged != null)
            {
                OnAccelReadingChanged(this, new EventArgs());
            }
        }

        void accel_Shaken(Accelerometer sender, AccelerometerShakenEventArgs args)
        {
            AccelLastShaken = args.Timestamp;
            if (OnShaken != null)
            {
                
                OnShaken(this, new EventArgs());
            }
        }

        void gyro_ReadingChanged(Gyrometer sender, GyrometerReadingChangedEventArgs args)
        {
            GyroX = args.Reading.AngularVelocityX;
            GyroY = args.Reading.AngularVelocityY;
            GyroZ = args.Reading.AngularVelocityZ;
            GyroLastReading = args.Reading.Timestamp;
            if (OnGyroReadingChanged != null)
            {
                OnGyroReadingChanged(this, new EventArgs());
            }
        }

        void light_ReadingChanged(LightSensor sender, LightSensorReadingChangedEventArgs args)
        {
            LightLux = args.Reading.IlluminanceInLux;
            LightLastReading = args.Reading.Timestamp;
            if (OnLightReadingChanged != null)
            {
                OnLightReadingChanged(this, new EventArgs());
            }
        }

        void incline_ReadingChanged(Inclinometer sender, InclinometerReadingChangedEventArgs args)
        {
            InclineX = args.Reading.PitchDegrees;
            InclineY = args.Reading.RollDegrees;
            InclineZ = args.Reading.YawDegrees;
            InclineLastReading = args.Reading.Timestamp;
            if (OnInclineReadingChanged != null)
            {
                OnInclineReadingChanged(this, new EventArgs());
            }
        }

        /// <summary>
        /// This stops the Ultrabook changing to portrait orientation when the user steers
        /// </summary>
        public void LockOrientation()
        {
            DisplayProperties.AutoRotationPreferences = DisplayOrientations.Landscape;
        }
    }
}
